package com.fy.common.handler;

import com.alibaba.fastjson.JSON;
import com.fy.common.exception.BusinessException;
import com.fy.common.enums.ErrorType;

import com.fy.common.model.ResponseError;
import com.fy.common.spring.I18nHelper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestControllerAdvice
public class AppExceptionHandler extends ResponseEntityExceptionHandler {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @ExceptionHandler(value = BusinessException.class)
    public ResponseEntity<ResponseError> businessExceptionHandler(BusinessException ex, HttpServletRequest request) {
        ResponseError error=new ResponseError(ex.getErrorType().getErrorCode(), I18nHelper.getMessage(ex.getErrorType().getErrorKey(),ex.getParam()));
        logger.warn("业务异常:\n{}\n异常信息:",getMessage(request),ex);
        return ResponseEntity.badRequest().body(error);
    }
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        List<ObjectError> errors =ex.getBindingResult().getAllErrors();
        StringBuilder errorMsg=new StringBuilder();
        errors.forEach(x -> errorMsg.append(x.getDefaultMessage()).append(";"));
        ResponseError error=new ResponseError(ErrorType.ARGUMENT_NOT_VALID.getErrorCode(),errorMsg.toString());
        return ResponseEntity.status(status).body(error);
    }

    @Override
    protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        List<ObjectError> errors =ex.getBindingResult().getAllErrors();
        StringBuilder errorMsg=new StringBuilder();
        errors.forEach(x -> errorMsg.append(x.getDefaultMessage()).append(";"));
        ResponseError error=new ResponseError(ErrorType.ARGUMENT_NOT_VALID.getErrorCode(),errorMsg.toString());
        return ResponseEntity.status(status).body(error);
    }

    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest webRequest) {
        ResponseError error=new ResponseError(ErrorType.SYSTEM_ERROR.getErrorCode(),ex.getMessage());
        ServletWebRequest servletRequest= (ServletWebRequest) webRequest;
        HttpServletRequest request = servletRequest.getRequest();

        logger.warn("系统异常:\n{}\n异常信息:",getMessage(request),ex);
        return super.handleExceptionInternal(ex, error, headers, status, webRequest);
    }

    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<ResponseError> exceptionHandler(Exception ex,HttpServletRequest request) {
        ResponseError error=new ResponseError(ErrorType.SYSTEM_ERROR.getErrorCode(), I18nHelper.getMessage(ErrorType.SYSTEM_ERROR.getErrorKey()));
        logger.error("系统异常:\n{}\n异常信息:",getMessage(request),ex);
        return ResponseEntity.badRequest().body(error);
    }

    public static String getMessage(HttpServletRequest request){
        String message="url={0} \nmethod={1}\nheaders={2}\nqueryParameters={3}\nbody={4}";

        //headers
        Enumeration<String> headerNames = request.getHeaderNames();
        Map<String,String> headers=new HashMap<>();
        while(headerNames.hasMoreElements()){
            String name = headerNames.nextElement();
            headers.put(name,request.getHeader(name));
        }
        //queryParameters
        Map<String, String[]> queryParameters = request.getParameterMap();

        //body
        String body="";
        if (request instanceof ContentCachingRequestWrapper) {
            ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
            body=StringUtils.toEncodedString(wrapper.getContentAsByteArray(), Charset.forName(wrapper.getCharacterEncoding()));
        }
        return MessageFormat.format(message,
                        request.getRequestURL(),
                        request.getMethod(),
                        JSON.toJSONString(headers),
                        JSON.toJSONString(queryParameters),
                        body);
    }

}
